package com.sztx.pay.center.rpc.component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.mortbay.log.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.util.CollectionUtils;

import com.alibaba.dubbo.common.logger.LogMsgNoConverter;
import com.alibaba.fastjson.JSONObject;
import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.Constance.BindCardType;
import com.sztx.pay.center.common.util.Constance.CallBackOrderState;
import com.sztx.pay.center.common.util.Constance.CardType;
import com.sztx.pay.center.common.util.Constance.PayFlowState;
import com.sztx.pay.center.common.util.Constance.RefundOrderState;
import com.sztx.pay.center.common.util.Constance.TradeMessageType;
import com.sztx.pay.center.common.util.Constance.TradeOrderType;
import com.sztx.pay.center.common.util.ValidateUtil;
import com.sztx.pay.center.core.service.AccountService;
import com.sztx.pay.center.core.service.BillnoService;
import com.sztx.pay.center.core.service.CallBackService;
import com.sztx.pay.center.core.service.MqMessageService;
import com.sztx.pay.center.core.service.OrderMappingService;
import com.sztx.pay.center.core.service.PayCoreCallBack;
import com.sztx.pay.center.core.service.PayCoreService;
import com.sztx.pay.center.core.service.RiskControlService;
import com.sztx.pay.center.core.service.SettleService;
import com.sztx.pay.center.core.service.bean.CallBackInfo;
import com.sztx.pay.center.core.service.bean.PayCoreRefund;
import com.sztx.pay.center.core.service.bean.PayCoreResult;
import com.sztx.pay.center.core.service.bean.PayCoreTradeInfo;
import com.sztx.pay.center.core.service.bean.PayeeInfo;
import com.sztx.pay.center.core.service.bean.SettleRequest;
import com.sztx.pay.center.core.service.util.SettleTradeType;
import com.sztx.pay.center.core.service.util.SettleType;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderB2cMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderConfirmDetailMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.mysql.OrderRefundMysqlDAO;
import com.sztx.pay.center.dataaccess.dao.redis.LockRedisDAO;
import com.sztx.pay.center.dataaccess.domain.OrderB2cDO;
import com.sztx.pay.center.dataaccess.domain.OrderConfirmDetailDO;
import com.sztx.pay.center.dataaccess.domain.OrderRefundDO;
import com.sztx.pay.center.dataaccess.domain.UserActDO;
import com.sztx.pay.center.dataaccess.domain.UserBindCardDO;
import com.sztx.pay.center.rpc.api.domain.ConfirmOrderRequest;
import com.sztx.pay.center.rpc.api.domain.RefundRequest;
import com.sztx.pay.center.rpc.api.domain.TradeBaseRequest;
import com.sztx.pay.center.rpc.api.domain.TradeFlowMessage;
import com.sztx.pay.center.rpc.api.domain.TradeResponse;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.common.util.StringUtil;

public class TradeRefundService extends TradeService implements PayCoreCallBack {

	OrderB2cMysqlDAO orderB2cMysqlDAO;
	
	@Autowired
	OrderMappingService orderMappingService;
	
	@Autowired
	CallBackService callBackService;
	
	@Autowired
	private LockRedisDAO lockRedisDAO;
	
	@Autowired
	private MqMessageService mqMessageService;

	@Autowired
	OrderConfirmDetailMysqlDAO orderConfirmDAO;
	
	@Autowired
	SettleService settleService;
	
	@Autowired
	TaskExecutor taskExecutor;
	
	@Autowired
	@Qualifier("transactionManager")
	private DataSourceTransactionManager txManager;
	
	public OrderB2cMysqlDAO getOrderB2cMysqlDAO() {
		return orderB2cMysqlDAO;
	}

	public void setOrderB2cMysqlDAO(OrderB2cMysqlDAO orderB2cMysqlDAO) {
		this.orderB2cMysqlDAO = orderB2cMysqlDAO;
	}

	public OrderRefundMysqlDAO getOrderRefundMysqlDAO() {
		return orderRefundMysqlDAO;
	}

	public void setOrderRefundMysqlDAO(OrderRefundMysqlDAO orderRefundMysqlDAO) {
		this.orderRefundMysqlDAO = orderRefundMysqlDAO;
	}

	public PayCoreService getPayCoreService() {
		return payCoreService;
	}

	public void setPayCoreService(PayCoreService payCoreService) {
		this.payCoreService = payCoreService;
	}

	public BillnoService getBillnoService() {
		return billnoService;
	}

	public void setBillnoService(BillnoService billnoService) {
		this.billnoService = billnoService;
	}

	public AccountService getAccountService() {
		return accountService;
	}

	public void setAccountService(AccountService accountService) {
		this.accountService = accountService;
	}

	public RiskControlService getRiskControlService() {
		return riskControlService;
	}

	public void setRiskControlService(RiskControlService riskControlService) {
		this.riskControlService = riskControlService;
	}

	public String getB2cTradeOrderId() {
		return b2cTradeOrderId;
	}

	public void setB2cTradeOrderId(String b2cTradeOrderId) {
		this.b2cTradeOrderId = b2cTradeOrderId;
	}

	OrderRefundMysqlDAO orderRefundMysqlDAO;
	
	PayCoreService payCoreService;
	
	BillnoService billnoService;
	
	AccountService accountService;
	
	RiskControlService riskControlService;
	
	private String b2cTradeOrderId;
	
	@Override
	void checkPrivateParam(Map<String, String> params) {
		String tradeOrderId = params.get("tradeOrderId");
		String orderId = params.get("orderId");
		String amount = params.get("amount");
		
		
		ValidateUtil.isNotBlank(tradeOrderId, "tradeOrderId不能为空!");
		OrderB2cDO b2cDO = orderB2cMysqlDAO.findByOrderIdAndId(tradeOrderId, orderId);
		if (b2cDO == null)
			throw new BusinessException("该交易订单不存在:[" + tradeOrderId + "]!");
		if (b2cDO.getOrderStatus().intValue() != Constance.B2COrderState.SUCCESS.getCode() && b2cDO.getOrderStatus().intValue() != Constance.B2COrderState.REFUND_FAIL.getCode())
			throw new BusinessException("当前订单状态不能退款!");
		params.put("payerUserId", Constance.ACT_SZTX_CASH);
		
		ValidateUtil.isNotBlank(amount, "amount不能为空");
		ValidateUtil.isTrue(StringUtil.isInteger(amount), "amount必须为整数");
		
		
		long refundAmount = Integer.parseInt(amount);
		long tradeAmount = b2cDO.getTradeAmount();
		
		if (refundAmount <= 0) {
			throw new BusinessException("订单"+tradeOrderId+"退款金金额必须大于0");
		}
		
		if (refundAmount > tradeAmount) {
			throw new BusinessException("订单"+tradeOrderId+"退款金金额大于实际交易金额");
		}
		
		params.put("refundAmount", refundAmount+"");
		
		
		
		
//		params.put("amount", b2cDO.getTradeAmount().toString());
		
		
		
		
	}

	@Override
	boolean isRepeatOrder(Map<String, String> params) {
		String orderId = params.get("orderId");
		
		boolean lockOrder = lockRedisDAO.lockOrder(orderId, "0", "checkRefundRepeat", 5L);
		if (!lockOrder) return true;
		
		OrderRefundDO orderRechargeDO = orderRefundMysqlDAO.findByOrderId(orderId);
		if (orderRechargeDO != null) {
			return true;
		}

		return false;
	}

	@Override
	String recordOrder(TradeBaseRequest request) {
		if (!(request instanceof RefundRequest)) {
			logger.error("请求参数错误request不是RefundRequest对象");
			throw new BusinessException("服务器正忙，请稍后再试");
		}
		RefundRequest refundRequest = (RefundRequest) request;
		String tradeOrderId = refundRequest.getTradeOrderId();
		String attach = refundRequest.getAttach();
		String expireTime = refundRequest.getExpireTime();
		String notifyUrl = refundRequest.getNotifyUrl();
		String orderId = refundRequest.getOrderId();
		String orderTime = refundRequest.getOrderTime();
		String returnUrl = refundRequest.getReturnUrl();
		String sign = refundRequest.getSign();
		String signType = refundRequest.getSignType();
		String srcIp = refundRequest.getSrcIp();
		String srcChannel = refundRequest.getSrcChannel();
		String refundOrderId = billnoService.nextRefundNo();
		
		OrderB2cDO b2cDO = orderB2cMysqlDAO.findById(tradeOrderId);
		String payerUserAct = b2cDO.getPayerUserAct();
		Long tradeAmount = b2cDO.getTradeAmount();
		Long refundAmount = Long.valueOf(refundRequest.getAmount());
		String b2cOrderId = b2cDO.getOrderId();
		String payerUserId = b2cDO.getPayerUserId();
		
		OrderRefundDO orderRefundDO = new OrderRefundDO();
		orderRefundDO.setPayerUserAct(payerUserAct);
		orderRefundDO.setAddTime(new Date());
		orderRefundDO.setDescript("");
		orderRefundDO.setInnerStatus(1);
		orderRefundDO.setNotifyUrl(notifyUrl);
		orderRefundDO.setOrderId(orderId);
		orderRefundDO.setPayAmount(tradeAmount);
		orderRefundDO.setPayTime(null);
		orderRefundDO.setReferUserId(null);
		orderRefundDO.setRefundAmount(refundAmount);
		orderRefundDO.setRefundChannel(new Byte(srcChannel));
		orderRefundDO.setRefundFee(0L);
		orderRefundDO.setRefundOrderId(refundOrderId);
		orderRefundDO.setOrderStatus((byte)Constance.RefundOrderState.REFUND_STATUS_INIT.getCode());
		orderRefundDO.setOrderDesc(Constance.RefundOrderState.REFUND_STATUS_INIT.getDesc());
		orderRefundDO.setRefundType((byte)Constance.RefundType.B2C.getCode());
		orderRefundDO.setRemark(attach);
		orderRefundDO.setReturnUrl(returnUrl);
		orderRefundDO.setSourceIp(srcIp);
		orderRefundDO.setSrcOrderId(tradeOrderId);
		orderRefundDO.setSrcOutOrderId(b2cOrderId);
		orderRefundDO.setUserId(payerUserId);
		
		orderRefundMysqlDAO.save(orderRefundDO);
		this.b2cTradeOrderId = tradeOrderId;
		return refundOrderId;
	}

	@Override
	UserBindCardDO getPayerBindInfo(Map<String, String> params) {
		return null;
	}

	@Override
	UserBindCardDO getPayeeBindInfo(Map<String, String> params) {
		return null;
	}

	@Override
	UserActDO getPayerActInfo(TradeBaseRequest request) {
		return null;
	}

	@Override
	UserActDO getPayeeActInfo(TradeBaseRequest request) {
		return null;
	}

	@Override
	TradeResponse invokePayCore(Map<String, String> params) {
		String tradeOrderId = params.get("tradeOrderId");
		OrderB2cDO b2cDO = orderB2cMysqlDAO.findById(this.b2cTradeOrderId);
		Integer refundAmount = Integer.parseInt(params.get("refundAmount"));
		

		String originChargeOrderId = orderMappingService.getMappingOrderId(this.b2cTradeOrderId, (byte)Constance.PayFlowType.PAY.getCode());        //原交易支付订单号
		String originTradeOrderId = orderMappingService.getMappingOrderId(this.b2cTradeOrderId, (byte)Constance.PayFlowType.BALANCE_TRADE.getCode());        //原交易支付订单号
		
		final PayCoreRefund refund = new PayCoreRefund();
		refund.setRefundOrderId(tradeOrderId);		
		refund.setOriginTradeOrderId(originTradeOrderId);
		refund.setAmount(refundAmount);
		refund.setOriginChargeOrderId(originChargeOrderId);
		refund.setAttach("b2c交易退款");
		refund.setBusinessType(b2cDO.getBusinessType());
		OrderB2cDO orderB2cDO = new OrderB2cDO();
		orderB2cDO.setTradeOrderId(this.b2cTradeOrderId);
		orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUNDING.getCode());
		orderB2cDO.setOrderDesc(Constance.B2COrderState.REFUNDING.getDesc());
		orderB2cMysqlDAO.updateInfo(orderB2cDO);
		//更新退款订单为退款中
		OrderRefundDO updateRefundDo = new OrderRefundDO();
		updateRefundDo.setOrderStatus((byte)Constance.RefundOrderState.REFUND_STATUS_IN.getCode());
		updateRefundDo.setOrderDesc(Constance.RefundOrderState.REFUND_STATUS_IN.getDesc());
		updateRefundDo.setRefundOrderId(tradeOrderId);
		orderRefundMysqlDAO.update(updateRefundDo);
		final String msgno = LogMsgNoConverter.getCurrentMsgno();
		//异步调用网关退款接口
		taskExecutor.execute(new Runnable() {
			@Override
			public void run() {
				try {
					LogMsgNoConverter.setMsgno(msgno);
					PayCoreResult result = payCoreService.refund(refund , "tradeRefundService");
					handRefundResult(result);
				} catch (Exception e) {
					logger.error("", e);
				}finally{
					LogMsgNoConverter.clear(); //重新生成msgno
				}
			}
		});
		
		TradeResponse response = new TradeResponse();
		response.setTradeOrderId(tradeOrderId);			
		response.setResultCode("2");
		response.setResultMsg("退款中");
		return response;
		
		
//		PayCoreResult innerTransfer = innerTransfer("", payerUserId, payerAccountId, payerUserType, userId, 
//				userBalanceActInfo.getActNo(), Constance.UserType.valueOf(userBalanceActInfo.getUserType()), 
//				tradeOrderId,payerTfActNo,payeeTfActNo);
//		int tradeSataus = innerTransfer.getTradeSataus();
//		OrderB2cDO orderB2cDO = new OrderB2cDO();
//		orderB2cDO.setTradeOrderId(this.b2cTradeOrderId);
//		orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUNDING.getCode());
//		int orderStatus = 0;
//		long payAmount = 0l;
//		if (tradeSataus == Constance.PayFlowState.PAYING.getCode()) {
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_IN.getCode();
//		}
//		if (tradeSataus == Constance.PayFlowState.SUCCESS.getCode()){
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_SUCCESS.getCode();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_SUCCESS.getCode());
//			payAmount = this.payAmount;
//		}
//		if (tradeSataus == Constance.PayFlowState.FAIL.getCode()){
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_FAIL.getCode();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_FAIL.getCode());			
//		}
//		if (tradeSataus == Constance.PayFlowState.EXCEPTION.getCode()){
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_EXCEPTION.getCode();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_EXCEPTION.getCode());			
//		}
//		
//		OrderRefundDO orderRefundDO = new OrderRefundDO();
//		orderRefundDO.setRefundOrderId(tradeOrderId);
//		orderRefundDO.setRefundStatus((byte) orderStatus);
//		orderRefundDO.setPayAmount(payAmount);
//		orderRefundMysqlDAO.update(orderRefundDO);
//		orderB2cMysqlDAO.updateInfo(orderB2cDO );
//		callBack(tradeOrderId, orderStatus);
//		
//		TradeResponse response = new TradeResponse();
//		response.setResultCode(String.valueOf(tradeSataus));
//		response.setTradeOrderId(tradeOrderId);
//		return response;
	}

	@Override
	void handerPayCoreResult() {

	}
	

	@Override
	public void callPayResult(PayCoreTradeInfo tradeInfo) {
		String referOrderId = tradeInfo.getReferOrderId();
//		OrderRefundDO refundDO = orderRefundMysqlDAO.findById(referOrderId);
//		OrderB2cDO orderB2cDO = new OrderB2cDO();
//		PayFlowState payFlowState = tradeInfo.getPayFlowState();
//		int orderStatus = 0;
//		long payAmount = 0l;
//		orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUNDING.getCode());
//		orderB2cDO.setTradeOrderId(refundDO.getSrcOrderId());
//		if (payFlowState.getCode() == Constance.PayFlowState.SUCCESS.getCode()){
//			orderStatus  = Constance.RefundOrderState.REFUND_STATUS_SUCCESS.getCode();
//			payAmount = refundDO.getRefundAmount();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_SUCCESS.getCode());
//		}
//		if (payFlowState.getCode() == Constance.PayFlowState.FAIL.getCode()){
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_FAIL.getCode();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_FAIL.getCode());			
//		}
//		if (payFlowState.getCode() == Constance.PayFlowState.EXCEPTION.getCode()){
//			orderStatus = Constance.RefundOrderState.REFUND_STATUS_EXCEPTION.getCode();
//			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_EXCEPTION.getCode());			
//		}
//		
//		OrderRefundDO orderRefundDO = new OrderRefundDO();
//		orderRefundDO.setRefundOrderId(referOrderId);
//		orderRefundDO.setRefundStatus((byte) orderStatus);
//		orderRefundDO.setPayAmount(payAmount);
//		orderRefundMysqlDAO.update(orderRefundDO);
//		
//		orderB2cMysqlDAO.updateInfo(orderB2cDO );
//		callBack(referOrderId, orderStatus);
		
		PayCoreResult payCoreResult = new PayCoreResult();
		payCoreResult.setReferOrderId(referOrderId);
		payCoreResult.setPayFlowNo(tradeInfo.getPayCoreOrderId());
		payCoreResult.setTradeSataus(tradeInfo.getPayFlowState().getCode());
		payCoreResult.setTradeDesc(tradeInfo.getPayFlowDesc());
		payCoreResult.setChannelId(tradeInfo.getChannelId());
		payCoreResult.setChannelBankId(tradeInfo.getChannelBankId());
		
		handRefundResult(payCoreResult);
	}
	
	@Transactional
	private TradeResponse handRefundResult(PayCoreResult result){	
		
		Log.info("HandRefundResult:"+JSONObject.toJSONString(result));
		
		TradeResponse response = null;

		String referOrderId = result.getReferOrderId();
		
		DefaultTransactionDefinition def = new DefaultTransactionDefinition();
		def.setName("com.sztx.pay.center.rpc.component.TradeRefundService.handRefundResult");
		def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
		TransactionStatus transactionStatus = txManager.getTransaction(def);
		int refundSatus = 1;
		String refundDesc = null;
		String orderDesc = null;
		try {
			OrderRefundDO refundDO = orderRefundMysqlDAO.findByIdLock(referOrderId);
			Log.info("refundOrderId:" + referOrderId);
			Long refundAmount = refundDO.getRefundAmount();
			Long payAmount = refundDO.getPayAmount();
			String b2cOrderId = refundDO.getSrcOrderId();
			Long realPayAmount = payAmount - refundAmount;
			PayFlowState payFlowState = PayFlowState.valueOf(result.getTradeSataus());
			refundSatus = refundDO.getOrderStatus();
			
			refundDesc = result.getTradeDesc();		
			
			//只允许退款初始化订单和退款中订单继续处理
			if (refundSatus != RefundOrderState.REFUND_STATUS_INIT.getCode() && refundSatus != RefundOrderState.REFUND_STATUS_IN.getCode()) {
				response = new TradeResponse();
				response.setTradeOrderId(referOrderId);			
				response.setResultCode(refundSatus+"");
				response.setResultMsg(refundDO.getRemark());
				return response;	
			}
//			int orderStatus = 0;
//			long payAmount = 0l;
			OrderB2cDO orderB2cDO = new OrderB2cDO();
			orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUNDING.getCode());
			orderB2cDO.setTradeOrderId(refundDO.getSrcOrderId());		
			
			String channelId = null;
			OrderRefundDO orderRefundDO = new OrderRefundDO();
			if (payFlowState.getCode() == Constance.PayFlowState.SUCCESS.getCode()){
				refundSatus  = Constance.RefundOrderState.REFUND_STATUS_SUCCESS.getCode();
				orderDesc  = Constance.RefundOrderState.REFUND_STATUS_SUCCESS.getDesc();
//				payAmount = refundDO.getRefundAmount();
				orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_SUCCESS.getCode());
				orderB2cDO.setOrderDesc(Constance.B2COrderState.REFUND_SUCCESS.getDesc());
				channelId = result.getChannelId();
				logger.info("refundAmount:" + refundAmount);
				logger.info("payAmount:" + payAmount);
				logger.info("realPayAmount:" + realPayAmount);
				if (refundAmount.compareTo(payAmount) != 0) {
					//进行结算(写入结算订单)
					OrderB2cDO b2cDO = orderB2cMysqlDAO.findById(refundDO.getSrcOrderId());
					long realFee = recordRefundSettle(b2cDO, realPayAmount);
					//修改b2c订单的payAmount
					orderB2cDO.setPayAmount(realPayAmount);
					orderB2cDO.setFee((int)realFee);
					//修改refund订单的payAmount
					orderRefundDO.setPayAmount(realPayAmount);
				} else {
					orderB2cDO.setPayAmount(0l);
					orderB2cDO.setFee(0);
				}
			}
			if (payFlowState.getCode() == Constance.PayFlowState.FAIL.getCode()){
				refundSatus = Constance.RefundOrderState.REFUND_STATUS_FAIL.getCode();
				orderDesc  = Constance.RefundOrderState.REFUND_STATUS_FAIL.getDesc();
				orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_FAIL.getCode());
				orderB2cDO.setOrderDesc(Constance.B2COrderState.REFUND_FAIL.getDesc());
				channelId = result.getChannelId();
			}
			if (payFlowState.getCode() == Constance.PayFlowState.EXCEPTION.getCode()){
				refundSatus = Constance.RefundOrderState.REFUND_STATUS_EXCEPTION.getCode();
				orderDesc  = Constance.RefundOrderState.REFUND_STATUS_EXCEPTION.getDesc();
				orderB2cDO.setOrderStatus(Constance.B2COrderState.REFUND_EXCEPTION.getCode());	
				orderB2cDO.setOrderDesc(Constance.B2COrderState.REFUND_EXCEPTION.getDesc());
				channelId = result.getChannelId();
			}
			
			orderRefundDO.setRefundOrderId(referOrderId);
			orderRefundDO.setOrderStatus((byte) refundSatus);
			orderRefundDO.setOrderDesc(orderDesc);
			orderRefundDO.setRemark(refundDesc);
			orderRefundDO.setPayChannelId(channelId);
//			orderRefundDO.setPayAmount(payAmount);
			orderRefundMysqlDAO.update(orderRefundDO);
			
			orderB2cMysqlDAO.updateInfo(orderB2cDO );
			
			String msgNo = LogMsgNoConverter.getCurrentMsgno();
			
			taskExecutor.execute(new RefundCallBack(referOrderId, refundSatus, result.getChannelId(), refundDO.getRemark(), msgNo));
		} catch (Exception ex)  {
			txManager.rollback(transactionStatus);
			logger.error("处理退款结果出错", ex);
			throw new BusinessException(ex);
		}finally{
			if (!transactionStatus.isCompleted()) {
				txManager.commit(transactionStatus);
			}			
		}
		
		response = new TradeResponse();
		response.setTradeOrderId(referOrderId);
		response.setResultCode(result.getTradeSataus()+"");
		response.setResultMsg(StringUtil.isBlank(refundDesc) ? orderDesc : refundDesc);
		return response;	
	}
	
	
	
	
	private Long recordRefundSettle(OrderB2cDO orderB2cDO, Long realPayAmount) {
		
		CardType cardType = null;
		
		String bindNo = orderB2cDO.getPayerBindNo();
		String payerUserId = orderB2cDO.getPayerUserId();
		String bankId = orderB2cDO.getPayBankId();
		
		UserBindCardDO userBindCardDO = null;
		
		if (!Constance.BERBON_PAY_BANKID.equals(bankId)) {
			userBindCardDO = accountService.findUserBindInfoIgnoreState(bindNo, payerUserId, BindCardType.BIND_QUICK_PAY);
		}
		
		if(userBindCardDO != null && userBindCardDO.getCardType() != null){
			cardType = CardType.valueOf(userBindCardDO.getCardType());
		}
		//计算实际结算金额的结算手续费
		long calculateHandlingFee = settleService.calculateHandlingFee(SettleTradeType.TRADE, SettleType.LATTER, orderB2cDO.getPayeeUserId(), realPayAmount,orderB2cDO.getPlatChannelId(),orderB2cDO.getPayBankId(),cardType);
		if (calculateHandlingFee > realPayAmount) {
			calculateHandlingFee = realPayAmount;
		}
		long remainAmount = realPayAmount - calculateHandlingFee;
		
		//确认收货记录信息
		List<ConfirmOrderRequest> confirmOrderRequests = new ArrayList<ConfirmOrderRequest>();
		
		//组装结算信息
		List<PayeeInfo> payeeInfos = new ArrayList<PayeeInfo>();
		SettleRequest request = new SettleRequest();
		
		if(remainAmount != 0) {
			//结算信息
			PayeeInfo info = new PayeeInfo();
			info.setAmount(remainAmount);
			info.setPayeeUser(orderB2cDO.getPayeeUserId());
			info.setTradeOrderType(TradeOrderType.SETTLE_ORDER);
			payeeInfos.add(info);
			//确认收货记录信息
			ConfirmOrderRequest confirmOrderRequest = new ConfirmOrderRequest();
			confirmOrderRequest.setOutOrderId(orderB2cDO.getOrderId());
			confirmOrderRequest.setTradeOrderId(orderB2cDO.getTradeOrderId());
			confirmOrderRequest.setAmount(remainAmount);
			confirmOrderRequest.setRemark("交易结算给商家");
			confirmOrderRequest.setUserId(orderB2cDO.getPayeeUserId());
			confirmOrderRequests.add(confirmOrderRequest);
		}
		
		request.setHandingFee(calculateHandlingFee);
		request.setPayerUser(orderB2cDO.getPayeeUserId());
		request.setPayeeInfo(payeeInfos);
		request.setOrderId(orderB2cDO.getTradeOrderId());
		request.setAttach("确认收货结算");
		request.setPerPayeeHandingFee(false);
		request.setBusinessType(orderB2cDO.getBusinessType());
		
		recordConfirmDetail(confirmOrderRequests, orderB2cDO.getTradeOrderId(), orderB2cDO.getOrderId());
		settleService.settleLatter(request, "confirmOrderServiceImpl");
		return calculateHandlingFee;
	}

	private void recordConfirmDetail(List<ConfirmOrderRequest> confirmOrderRequests,String tradeOrderId,String outOrderId){
		if(CollectionUtils.isEmpty(confirmOrderRequests)){
			return;
		}
		List<OrderConfirmDetailDO> orderConfirmDetailDOs = orderConfirmDAO.findByTradeOrderId(tradeOrderId);
		if(CollectionUtils.isEmpty(orderConfirmDetailDOs)){
			for (ConfirmOrderRequest confirmOrderRequest : confirmOrderRequests) {
				OrderConfirmDetailDO orderConfirmDetailDO = new OrderConfirmDetailDO();
				orderConfirmDetailDO.setTradeOrderId(confirmOrderRequest.getTradeOrderId());
				orderConfirmDetailDO.setOutOrderId(confirmOrderRequest.getOutOrderId());
				orderConfirmDetailDO.setAmount(confirmOrderRequest.getAmount());
				orderConfirmDetailDO.setUserId(confirmOrderRequest.getUserId());
				orderConfirmDetailDO.setRemark(confirmOrderRequest.getRemark());
				orderConfirmDetailDOs.add(orderConfirmDetailDO);
			}
			Log.info("orderConfirmDetailDOs:"+JSONObject.toJSONString(orderConfirmDetailDOs));
			orderConfirmDAO.batchsave(orderConfirmDetailDOs);
		}else{
			List<ConfirmOrderRequest> confirmDaoOrderRequests = new ArrayList<ConfirmOrderRequest>();
			for (OrderConfirmDetailDO orderConfirmDetailDO : orderConfirmDetailDOs) {
				ConfirmOrderRequest confirmOrderRequest = new ConfirmOrderRequest();
				confirmOrderRequest.setOutOrderId(orderConfirmDetailDO.getOutOrderId());
				confirmOrderRequest.setTradeOrderId(orderConfirmDetailDO.getTradeOrderId());
				confirmOrderRequest.setAmount(orderConfirmDetailDO.getAmount());
				confirmOrderRequest.setRemark(orderConfirmDetailDO.getRemark());
				confirmOrderRequest.setUserId(orderConfirmDetailDO.getUserId());
				confirmDaoOrderRequests.add(confirmOrderRequest);
			}
			if(confirmDaoOrderRequests.size() == confirmOrderRequests.size() && confirmDaoOrderRequests.contains(confirmOrderRequests)){
				Log.info("重复发起确认收货,不作记录");
			}else{
				throw new BusinessException("订单【"+outOrderId+"】确认收货信息与之前提交信息不一致!");
			}
			
		}
	}
	@Async
	private void callBack(String refundOrderId,int state, String channelId, String attach){
		Date payTime = new Date();
		OrderRefundDO orderRefundDO = orderRefundMysqlDAO.findById(refundOrderId);
		//通知业务系统
		RefundOrderState refundOrderState = RefundOrderState.valueOf(state);
		CallBackOrderState callBackOrderState = null;
		if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_SUCCESS)){
			callBackOrderState = CallBackOrderState.SUCCESS;
			
			TradeFlowMessage message = new TradeFlowMessage();
			OrderB2cDO b2cOrder = orderB2cMysqlDAO.findById(orderRefundDO.getSrcOrderId());
			
			message.setTradeType(TradeMessageType.REFUND.getCode());
			message.setBerbonAcc(orderRefundDO.getUserId());
			message.setBusinessType(b2cOrder.getBusinessType());
			message.setTradeAmount(b2cOrder.getTradeAmount());
			message.setReceiveAmount(orderRefundDO.getRefundAmount());
			message.setOtherBerbonAcc(null);
			message.setPayOrderNo(refundOrderId);
			message.setTradeOrderNo(b2cOrder.getOrderId());
			message.setFee(orderRefundDO.getRefundFee());
			
			sendTradeFlowMessage(message);
		}else if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_FAIL)){
			callBackOrderState = CallBackOrderState.FAIL;
		}else if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_EXCEPTION)){
			callBackOrderState = CallBackOrderState.EXCEPTION;
		}else{
			return;
		}
		
		CallBackInfo callBackInfo = new CallBackInfo();
		callBackInfo.setTradeOrderId(refundOrderId);
		callBackInfo.setOutOrderId(orderRefundDO.getOrderId());
		callBackInfo.setNotfiyUrl(orderRefundDO.getNotifyUrl());
		callBackInfo.setReturnUrl(orderRefundDO.getReturnUrl());
		callBackInfo.setTotalFee(0);
		callBackInfo.setPayAmount(orderRefundDO.getRefundAmount().intValue());
		callBackInfo.setAttach(orderRefundDO.getRemark());
		callBackInfo.setPayTime(payTime);
		callBackInfo.setTradeCrateTime(orderRefundDO.getAddTime());
		callBackInfo.setOrderType(TradeOrderType.REFUND_ORDER);
		callBackInfo.setOrderState(callBackOrderState);
		callBackService.callBack(callBackInfo );
	}

	private boolean sendTradeFlowMessage(TradeFlowMessage message) {
		String json = JSONObject.toJSONString(message);
		mqMessageService.sendTradeFlowMsg(json);
		return true;
	}

class RefundCallBack implements Runnable {
		
		protected Logger logger = LoggerFactory.getLogger(this.getClass());
		
		String refundOrderId;
		int state;
		String channelId; 
		String attach;
		String msgNo;
		
		
		public RefundCallBack(String refundOrderId, int state, String channelId, String attach, String msgNo) {
			super();
			this.refundOrderId = refundOrderId;
			this.state = state;
			this.channelId = channelId;
			this.attach = attach;
			this.msgNo = msgNo;
		}



		@Override
		public void run() {
			try {

				LogMsgNoConverter.setMsgno(msgNo);
				
				Date payTime = new Date();
				OrderRefundDO orderRefundDO = orderRefundMysqlDAO.findById(refundOrderId);
				//通知业务系统
				RefundOrderState refundOrderState = RefundOrderState.valueOf(state);
				CallBackOrderState callBackOrderState = null;
				if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_SUCCESS)){
					callBackOrderState = CallBackOrderState.SUCCESS;
					
					TradeFlowMessage message = new TradeFlowMessage();
					OrderB2cDO b2cOrder = orderB2cMysqlDAO.findById(orderRefundDO.getSrcOrderId());
					
					message.setTradeType(TradeMessageType.REFUND.getCode());
					message.setBerbonAcc(orderRefundDO.getUserId());
					message.setBusinessType(b2cOrder.getBusinessType());
					message.setTradeAmount(b2cOrder.getTradeAmount());
					message.setReceiveAmount(orderRefundDO.getRefundAmount());
					message.setOtherBerbonAcc(null);
					message.setPayOrderNo(refundOrderId);
					message.setTradeOrderNo(b2cOrder.getOrderId());
					message.setFee(orderRefundDO.getRefundFee());
					
					sendTradeFlowMessage(message);
				}else if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_FAIL)){
					callBackOrderState = CallBackOrderState.FAIL;
				}else if(refundOrderState.equals(RefundOrderState.REFUND_STATUS_EXCEPTION)){
					callBackOrderState = CallBackOrderState.EXCEPTION;
				}else{
					return;
				}
				
				CallBackInfo callBackInfo = new CallBackInfo();
				callBackInfo.setTradeOrderId(refundOrderId);
				callBackInfo.setOutOrderId(orderRefundDO.getOrderId());
				callBackInfo.setNotfiyUrl(orderRefundDO.getNotifyUrl());
				callBackInfo.setReturnUrl(orderRefundDO.getReturnUrl());
				callBackInfo.setTotalFee(0);
				callBackInfo.setPayAmount(orderRefundDO.getRefundAmount().intValue());
				callBackInfo.setAttach(orderRefundDO.getRemark());
				callBackInfo.setPayTime(payTime);
				callBackInfo.setTradeCrateTime(orderRefundDO.getAddTime());
				callBackInfo.setOrderType(TradeOrderType.REFUND_ORDER);
				callBackInfo.setOrderState(callBackOrderState);
				callBackService.callBack(callBackInfo );
			
			} catch (Exception e) {
				logger.error(refundOrderId+"订单回调通知失败", e);
			}finally{
				LogMsgNoConverter.clear();
			}
		}
		
	}
	
}
